﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace BReusable.FormSelection
{
	public partial class FormSelection : Form
	{
		/// <summary>
		/// Defines the function for getting the value from the main selection control
		/// </summary>
		public Func<object> GetSelection;

		/// <summary>
		/// Currently used for textboxes only to validate the string
		/// </summary>
		public Func<bool> ValidateSelection;

		public FormSelection()
		{
			InitializeComponent();
		}

		/// <summary>
		/// Called automatically when initialized with a listbox or combobox
		/// </summary>
		/// <param name="control"></param>
		public void AddMasterControl(Control control)
		{

			_tableLayoutPanel.Controls.Add(control, 0, 0);
			_tableLayoutPanel.SetColumnSpan(control, 2);
			control.Dock = DockStyle.Fill;

		}

		public FormSelection(TextBox textBox)
			: this()
		{
			AddMasterControl(textBox);
			GetSelection = () => textBox.Text;

		}

		public FormSelection(ListBox listBox)
			: this()
		{

			AddMasterControl(listBox);
			GetSelection = () => listBox.SelectedItem;
			listBox.DoubleClick += (sender, e) =>

					ValidateSubmit();


		}
		public FormSelection(CheckedListBox checkedListBox)
			: this()
		{
			AddMasterControl(checkedListBox);
			GetSelection = () => checkedListBox.CheckedItems;
		}
		public FormSelection(ComboBox comboBox)
			: this()
		{
			AddMasterControl(comboBox);
			GetSelection = () => comboBox.SelectedItem;
		}

		public void ValidateSubmit()
		{
			if ((GetSelection != null && GetSelection() == null) || (ValidateSelection != null && !ValidateSelection())) return;
			DialogResult = DialogResult.OK;
			Close();
		}

		public void Cancel()
		{
			DialogResult = DialogResult.Cancel;
			Close();
		}

		public void _btnOk_Click(object sender, EventArgs e)
		{
			ValidateSubmit();
		}

		public void _btnCancel_Click(object sender, EventArgs e)
		{
			Cancel();
		}

		/// <summary>
		/// If the user clicks OK and has an empty string, it will pass back the empty string
		/// </summary>
		/// <param name="title"></param>
		/// <param name="defaultText"></param>
		/// <param name="maxLength"></param>
		/// <param name="multiLine"></param>
		/// <param name="validator"></param>
		/// <returns></returns>
		public static String TextBoxInput(String title, String defaultText, int maxLength, bool multiLine, Func<String, bool> validator)
		{
			using (var textBox = new TextBox { Multiline = multiLine, MaxLength = maxLength })
			{
				if (defaultText.IsNullOrEmpty() == false) textBox.Text = defaultText;
				using (var formSelection = new FormSelection(textBox))
				{
					formSelection.Text = title;
					if(validator!=null)
					formSelection.ValidateSelection = () => validator(textBox.Text);
					return formSelection.ShowDialog() == DialogResult.OK ? textBox.Text.Trim() : null;
				}
			}

			
		}

		public static List<TClass> CheckedListBoxSelect<TClass>(IEnumerable<TClass> values, String title)
			where TClass : class
		{
			List<TClass> result = null;
			using (var checkedListBox = new CheckedListBox())
			{
				checkedListBox.CheckOnClick = true;
				checkedListBox.Items.AddRange(values.ToArray());
				
				using (var formSelection = new FormSelection(checkedListBox))
				{
					
					formSelection.Text = title;
					if (formSelection.ShowDialog() == DialogResult.OK)
					{
						result = new List<TClass>();
						var selection =(CheckedListBox.CheckedItemCollection) formSelection.GetSelection();
						foreach (var item in selection)
						{
							result.Add((TClass)item);
						}
						return result;
					}
				}
			}



			return result;

		}

		public static TClass ListBoxSelect<TClass>(IEnumerable<TClass> values, String title) where TClass : class
		{
			var result = (TClass)null;
			using (var listBox = new ListBox())
			{
				listBox.Items.AddRange(values.ToArray());
				
				using (var formSelection = new FormSelection(listBox))
				{
					formSelection.Text = title;
					if (formSelection.ShowDialog() == DialogResult.OK)
						return (TClass)formSelection.GetSelection();
				}
			}
			return result;
		}
		public static TClass ComboBoxSelect<TClass>(IEnumerable<TClass> values, String title) where TClass : class
		{
			var result = (TClass)null;
			using (var listBox = new ComboBox { DropDownStyle = ComboBoxStyle.DropDownList })
			{
				listBox.Items.AddRange(values.ToArray());

				using (var formSelection = new FormSelection(listBox))
				{
					formSelection.Text = title;
					if (formSelection.ShowDialog() == DialogResult.OK)
						return (TClass)formSelection.GetSelection();
				}
			}
			return result;
		}

		public static T? ListBoxSelectEnum<T>(String title) where T : struct
		{
			if (!typeof(T).IsEnum)
				return null;
			T? result = null;
			using (var listBox = new ListBox())
			{
				listBox.Items.AddRange(Enum.GetNames(typeof(T)));


				//listBox.Items.AddRange(values.ToArray());

				using (var formSelection = new FormSelection(listBox))
				{
					formSelection.Text = title;
					if (formSelection.ShowDialog() == DialogResult.OK)
						return (T)Enum.Parse(typeof(T), formSelection.GetSelection().ToString());
				}
			}
			return result;

		}

		public static T? ComboBoxSelectEnum<T>(String title) where T : struct
		{

			if (!typeof(T).IsEnum)
				return null;
			T? result = null;
			using (var comboBox = new ComboBox { DropDownStyle = ComboBoxStyle.DropDownList })
			{
				comboBox.Items.AddRange(Enum.GetNames(typeof(T)));


				//listBox.Items.AddRange(values.ToArray());

				using (var formSelection = new FormSelection(comboBox))
				{
					formSelection.Text = title;
					if (formSelection.ShowDialog() == DialogResult.OK)
						return (T)Enum.Parse(typeof(T), formSelection.GetSelection().ToString());
				}
			}
			return result;
		}



		private void FormSelection_Load(object sender, EventArgs e)
		{

		}






	}
}
